//和日志相关的函数
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <stdarg.h>
#include <unistd.h>
#include <sys/time.h>
#include <time.h>
#include <fcntl.h>
#include <errno.h>

#include "global.h"
#include "macro.h"
#include "function.h"
#include "configure.h"

//全局量
static u_char err_levels[][20] = {
	{"stderr"},
	{"emerh"},
	{"alert"},
	{"crit"},
	{"error"},
	{"warn"},
	{"notice"},
	{"info"},
	{"debug"}
};

log_t my_log;

//输出日志信息到标准设备
void LogStderr(int err, const char *fmt, ...) {
	va_list args;
	u_char errstr[MAX_ERROR_STR+1];
	u_char *p,*last;
	memset(errstr, 0, sizeof(errstr));
	last = errstr  + MAX_ERROR_STR;
	p = Cpymem(errstr,"monkey:", 7);
	
	va_start(args, fmt);
	p = Vslprintf(p, last, fmt, args);
	va_end(args);

	if(err) {
		p = LogErrno(p, last, err);
	}
	if(p >= (last-1)) {
		p = (last - 1) -1;
	}
 	*p++ = '\n';
	write(STDERR_FILENO, errstr, p-errstr);

	if(my_log.fd > STDERR_FILENO) {
		err = 0;
		p--;
		*p = 0;
		LogErrorCore(LOG_STDERR, err, (const char *)errstr);
	}
	return;
}


//将错误信息组合到给定内存中
u_char *LogErrno(u_char *buf, u_char *last, int err) {
	char *error_info  =strerror(err);
	size_t len = strlen(error_info);
	char left_str[10] = {0};
	sprintf(left_str, "(%d:",err);
	size_t left_len = strlen(left_str);
	char right_str[] = ")";
	size_t right_len = strlen(right_str);
	size_t extra_len = left_len + right_len;
	if((buf+len+extra_len) < last) {
		buf = Cpymem(buf, left_str, left_len);
		buf = Cpymem(buf, error_info, len);
		buf = Cpymem(buf, right_str, right_len);
	}
	return buf;
}


//往日志里写入日志
void LogErrorCore(int level, int err, const char *fmt, ...) {
	u_char *last;
	u_char errstr[MAX_ERROR_STR+1];
	memset(errstr,0,sizeof(errstr));
	last = errstr + MAX_ERROR_STR;

	struct timeval tv;
	struct tm      tm;
	time_t         sec;
	u_char         *p;
	va_list        args;

	memset(&tv, 0, sizeof(struct timeval));
	memset(&tm, 0, sizeof(struct tm));

	gettimeofday(&tv, NULL);
	sec = tv.tv_sec;
	localtime_r(&sec, &tm);
	tm.tm_mon++;
	tm.tm_year += 1900;

	u_char str_current_time[40] = {0};
	Slprintf(str_current_time, (u_char *)-1, "%4d/%02d/%02d %02d:%02d:%02d ", tm.tm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
	p = Cpymem(errstr,str_current_time,strlen((const char *)str_current_time));
	p = Slprintf(p, last, "[%s]", err_levels[level]);
	p = Slprintf(p, last, "%P:",current_pid);

	va_start(args, fmt);
	p = Vslprintf(p,last, fmt, args);
	va_end(args);

	if(err) {
		p = LogErrno(p, last, err);
	}
	if(p >= (last - 1)) {
		p = (last-1)-1;
	}
	*p++ = '\n';
	ssize_t n;
	while(1) {
		if(level > my_log.log_level) {
			break;
		}
		n = write(my_log.fd, errstr, p - errstr);
		if(n == -1) {
			if(errno == ENOSPC) {
				//写失败，磁盘没有空间
			}
			else {
				if(my_log.fd != STDERR_FILENO) {
					n = write(STDERR_FILENO, errstr, p-errstr);
				}
			}
		}
		break;
	}
	return;
}

//日志初始化
void LogInit() {
	u_char *log_name = NULL;
	size_t nlen;

	Configure *configure = Configure::GetInstance();
	log_name = (u_char*)configure->GetString("Log");
	if(log_name == NULL) {
		log_name = (u_char*)ERROR_LOG_PATH;
	}
	my_log.log_level = configure->GetIntDefault("LogLevel",LOG_NOTICE);

	my_log.fd = open((const char*)log_name,O_WRONLY|O_APPEND|O_CREAT,0644);
	if(my_log.fd == -1) {
		LogStderr(errno,"[alert] could not open error log file: open() \"%s\" failed", log_name);
		my_log.fd = STDERR_FILENO;
	}
	return;
}




